from __future__ import print_function

import base64
import logging
import os
import re
import time

import paramiko

logging.basicConfig(level=logging.DEBUG,
                    format='[%(asctime)s] %(levelname)s %(module)s:%(lineno)d %(message)s')

HOST = '10.9.70.40'
PORT = 22
USER = ''
PASS = ''

VIA_HOST = 'jump.sendcloud.io'
VIA_PORT = 22
VIA_USER = 'root'
VIA_PASS = 'fn1TWwJ9DmfrbK2Bk8ANEfJpyftKDz6YabxRHqJXPhvupWvn1o2sBql2vz47wvrm'

# PROJECT/feedbackloop/ssh.py
DIR_CURRENT = os.path.dirname(os.path.abspath(__file__))
DIR_PROJECT = os.path.dirname(DIR_CURRENT)


class SSHTool(object):
    def __init__(self, host, user, auth, via=None, via_user=None, via_auth=None):
        if via:
            t0 = paramiko.Transport(via)
            t0.start_client()
            t0.auth_password(via_user, via_auth)
            # setup forwarding from 127.0.0.1:<free_random_port> to |host|
            channel = t0.open_channel('direct-tcpip', host, ('127.0.0.1', 0))
            self.transport = paramiko.Transport(channel)
        else:
            self.transport = paramiko.Transport(host)
        self.transport.start_client()
        self.transport.auth_password(user, auth)

    def run(self, cmd):
        ch = self.transport.open_session()
        ch.set_combine_stderr(True)
        ch.exec_command(cmd)
        exit_status = ch.recv_exit_status()
        buf = ''
        while ch.recv_ready():
            buf += ch.recv(1024)
        return buf, exit_status


def main():
    # The example below is equivalent to
    # $ ssh 10.10.10.10 ssh 192.168.1.1 uname -a
    # The code above works as if these 2 commands were executed:
    # $ ssh -L <free_random_port>:192.168.1.1:22 10.10.10.10
    # $ ssh 127.0.0.1:<free_random_port> uname -a

    session = SSHTool((VIA_HOST, VIA_PORT), VIA_USER, VIA_PASS)
    # session = SSHTool((HOST, PORT), USER, PASS, via=(VIA_HOST, VIA_PORT), via_user=VIA_USER, via_auth=VIA_PASS)
    logging.info(session.run('uname -a'))


def receive(channel):
    data = ''
    if not channel.exit_status_ready():
        while True:
            time.sleep(0.1)
            if channel.recv_ready():
                _data = channel.recv(10240)
                logging.debug('get data: %s...', _data[:100])
                data += _data
                if _data.endswith(']# '):
                    break
            else:
                logging.debug('channel is not receive ready')
    else:
        logging.warn('channel exit')
    data = data.split('\r\n')[1]
    return data


def remote_execute(channel, command, show=False):
    logging.info('COMMAND: %r', command)
    channel.send(command + '\n')
    time.sleep(0.1)
    resp = receive(channel)
    if show:
        for line in resp.splitlines():
            logging.debug('RESPONSE: %r', line)
    return resp


RE_SH_ESCAPE = re.compile('(!|\$|#|&|\"|\'|\(|\)|\||<|>|`|\\\|;)')


def sh_escape(_s):
    return RE_SH_ESCAPE.sub(r'\\\1', _s)


def copy(channel, filepath):
    # TODO: escape
    _dir_name = os.path.dirname(filepath)
    _dir_name_escaped = sh_escape(_dir_name)
    _file_name = os.path.basename(filepath)
    _file_name_escaped = sh_escape(_file_name)
    remote_execute(channel, 'cd "%s"' % _dir_name_escaped)
    # remote_execute(channel, 'ls', show=True)
    # resp = remote_execute(channel, 'cat "%s"' % _file_name_escaped)
    remote_execute(channel, '_B64_RST=$(base64 -w0 "%s")' % _file_name_escaped)
    resp = remote_execute(channel, 'echo $_B64_RST')
    logging.debug(repr(resp))
    with open(os.path.join(DIR_PROJECT, 'tests', _file_name), 'wb') as _file:
        _file.write(base64.b64decode(resp))


def ssh_login():
    """
    z=$IFS; IFS=$(echo -en '\n\b'); (for i in $(ls); do [[ -f $i && ${i##*.} == 'eml' ]] && echo $i; done); IFS=$z


    tar czvf /tmp/softbounce.tgz /opt/softbounce/2018/07/31/153300449*
    tar czvf /tmp/softbounce_fbl.tgz /opt/softbounce_fbl/2018/07/31/
    tar czvf /tmp/softbounce_not_parsed.tgz /opt/softbounce_not_parsed/2018/07/31/1533004*
    tar czvf /tmp/softbounce_ignore.tgz /opt/softbounce_ignore/2018/07/31/153300449*
    tar czvf /tmp/softbounce_timeout_big.tgz /opt/softbounce_timeout_big/2018/
    tar czvf /tmp/softbounce_timeout_big2.tgz /opt/softbounce_timeout_big2/2018/07/
    tar czvf /tmp/softbounce_netease_fbl_register.tgz /opt/softbounce_netease_fbl_register/

    """
    try:
        c = paramiko.SSHClient()
        c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        c.connect(hostname=VIA_HOST, port=VIA_PORT, username=VIA_USER, password=VIA_PASS)

        if USER:
            command = 'ssh %s@%s' % (USER, HOST)
        else:
            command = 'ssh %s' % HOST

        channel = c.invoke_shell()
        remote_execute(channel, command, show=True)

        copy(channel, '/tmp/softbounce_netease_fbl_register.tgz')

        # stdin, stdout, stderr = c.exec_command(command + '\n')
        # logging.info('OVER')
        # stdin.write('ls')
        # logging.info('OVER')
        # stdin.flush()
        # logging.info('OVER')
        # logging.info('STDOUT: %r', stdout.readlines())
        # logging.info('STDERR: %r', stderr.readlines())

        # t = c.get_transport()
        # channel = t.open_session()
        # channel.get_pty()
        # # hang
        # print(channel.send(command))
        # print(channel.recv(1024))
        # channel = t.open_session()
        # print(channel.send('ls'))
        # print(channel.recv(1024))

        # command = 'uname -a'
        # command = 'pwd'
        # stdin, stdout, stderr = c.exec_command(command, get_pty=True)
        # logging.info(stdout.readlines())

        c.close()
    except Exception as e:
        logging.exception("Connection Failed: %s", e)

